#include "Rp2Tga.h"
#include "Rp2Renderer.h"

using namespace Rp2;

//---------------------------------------------------------------------------------------------------
Tga::Tga()
{
	m_acBits = 0;
	m_ulImageSize = 0;
	m_uiChannel = 0;
	m_eFormat = 0;
	m_iComponents = 0;
	m_uiLastBuffer = 0;
}
//---------------------------------------------------------------------------------------------------
Tga::~Tga()
{
}
//---------------------------------------------------------------------------------------------------
Image* Tga::LoadTGA(const unsigned char* aucBuffer, const std::string& rkFileName)
{

	Tga* pkTga = new Tga;;

	const unsigned char* pcCurrent = aucBuffer;

	// read header
	pcCurrent += System::Read1((const char*)pcCurrent, 18, (void*)&pkTga->m_kTgaHeader);

	// read format mode
	Image::FormatMode eFormat = Image::FormatMode::IT_QUANTITY;
	switch(pkTga->GetBitsPerPixel())
	{
	case 8:
		eFormat = Image::FormatMode::IT_INTENSITY8I;
		break;
	case 24:
		eFormat = Image::FormatMode::IT_BGR888;
		break;
	case 32:
		eFormat = Image::FormatMode::IT_BGRA8888;
		break;
	default:
		// unsupported format
		assert(false);
		break;
	}

	// get image size
	pkTga->m_uiChannel = pkTga->GetBitsPerPixel() / 8;
	pkTga->m_ulImageSize = pkTga->GetWidth() * pkTga->GetHeight() * pkTga->m_uiChannel;

	// allocate memory
	pkTga->m_acBits = new unsigned char[pkTga->m_ulImageSize];
	if (!pkTga->m_acBits)
	{
		System::MsgBoxPrintf(RP2_ERROR,TC("can not allocate memory"));
		return false;
	}
	
	// Read the image data
	System::Read1((const char*)pcCurrent, (int)pkTga->m_ulImageSize, pkTga->m_acBits);

	Image* pkImage = new Image(eFormat, pkTga->GetWidth(), pkTga->GetHeight(),
		pkTga->m_acBits, rkFileName.c_str());

	delete pkTga;
	pkTga = 0;

	return pkImage;
}
//---------------------------------------------------------------------------------------------------
bool Tga::ScreenToTGA(const char* acFileName, Renderer* pkRenderer)
{
	// display back buffer first
	pkRenderer->DisplayBackBuffer();

	FILE* pkFile;               // File pointer
	TGAHeader kTgaHeader;		// TGA file header
	unsigned long ulImageSize;  // Size in bytes of image
	char* acBits = NULL;		// Pointer to bits
	int aiViewport[4];          // Viewport in pixels
	int iLastBuffer;            // Storage for the current read buffer setting

	// get the viewport dimentions
	glGetIntegerv(GL_VIEWPORT, aiViewport);

	// image size(tga is tightly packed)
	ulImageSize = aiViewport[2] * aiViewport[3] * 3;
	acBits = (char*)malloc(ulImageSize);
	if (!acBits)
	{
		return false;
	}
	
	// read bits from color buffer
	glPixelStorei(GL_PACK_ALIGNMENT, 1);
	glPixelStorei(GL_PACK_ROW_LENGTH, 0);
	glPixelStorei(GL_PACK_SKIP_ROWS, 0);
	glPixelStorei(GL_PACK_SKIP_PIXELS, 0);

	// Get the current read buffer setting and save it. Switch to
	// the front buffer and do the read operation. Finally, restore
	// the read buffer state
	glGetIntegerv(GL_READ_BUFFER, (GLint*)&iLastBuffer);
	glReadBuffer(GL_FRONT);
	glReadPixels(0, 0, aiViewport[2], aiViewport[3], GL_BGR_EXT, GL_UNSIGNED_BYTE, acBits);
	glReadBuffer(iLastBuffer);

    // Initialize the Targa header
	kTgaHeader.cIDSize = 0;
	kTgaHeader.cColorMapType = 0;
	kTgaHeader.cImageType = 2;
	kTgaHeader.usColorMapStart = 0;
	kTgaHeader.usColorMapLength = 0;
	kTgaHeader.ucColorMapBits = 0;
	kTgaHeader.usXStart = 0;
	kTgaHeader.usYStart = 0;
	kTgaHeader.usWidth = aiViewport[2];
	kTgaHeader.usHeight = aiViewport[3];
	kTgaHeader.cBits = 24;
	kTgaHeader.cDescriptor = 0;

	// open file
	fopen_s(&pkFile, acFileName, "wb");
	if (!pkFile)
	{
		free(acBits);
		System::MsgBoxPrintf(RP2_ERROR,TC("Cannot open the .tga file"));
		return false;
	}

	// write header
	fwrite(&kTgaHeader, sizeof(TGAHeader), 1, pkFile);

	// write image data
	fwrite(acBits, ulImageSize, 1, pkFile);

	// free buffer and close file
	free(acBits);
	fclose(pkFile);

	return true;
}
//---------------------------------------------------------------------------------------------------
bool Tga::ReadTGA(const char* acFileName, Tga* pkTga)
{
	FILE* pkFile;

	// open file
	fopen_s(&pkFile, acFileName, "rb");
	if (!pkFile)
	{
		System::MsgBoxPrintf(RP2_ERROR, TC("Can not open %s for reading"), acFileName);
		return false;
	}

	// read header
	if(fread(&pkTga->m_kTgaHeader, 18, 1, pkFile) != 1)
	{
		System::MsgBoxPrintf(RP2_ERROR, TC("can not read tga header"));
		return false;
	}

	// check bit channels
	if (pkTga->GetBitsPerPixel() != 8 && pkTga->GetBitsPerPixel() != 24
		&& pkTga->GetBitsPerPixel() != 32)
	{
		System::MsgBoxPrintf(RP2_ERROR, TC("bits must be one of these: 8, 24, 32"));
		return false;
	}

	// get image size
	pkTga->m_uiChannel = pkTga->GetBitsPerPixel() / 8;
	pkTga->m_ulImageSize = pkTga->GetWidth() * pkTga->GetHeight() * pkTga->m_uiChannel;

	// allocate memory
	pkTga->m_acBits = new unsigned char[pkTga->m_ulImageSize];
	if (!pkTga->m_acBits)
	{
		System::MsgBoxPrintf(RP2_ERROR,TC("can not allocate memory"));
		return false;
	}

	// read in image data
	if (fread(pkTga->m_acBits, pkTga->m_ulImageSize, 1, pkFile) != 1)
	{
		System::MsgBoxPrintf(RP2_ERROR,TC("size %d can not read in image data"), (int)pkTga->m_ulImageSize);
		free(pkTga->m_acBits);
		return false;
	}

	// set opengl format
	switch(pkTga->m_uiChannel)
	{
	case 1:
		{
			pkTga->m_eFormat = GL_LUMINANCE;
			pkTga->m_iComponents = GL_LUMINANCE;
			break;
		}
	case 3:
		{
			pkTga->m_eFormat = GL_BGR;
			pkTga->m_iComponents = GL_RGB;
			break;
		}
	case 4:
		{
			pkTga->m_eFormat = GL_BGRA;
			pkTga->m_iComponents = GL_RGBA;
			break;
		}
	default:
		{
			System::MsgBoxPrintf(RP2_ERROR,TC("tga format uncorrect."));
			return false;
		}
	}
	
	// finish.
	fclose(pkFile);
	return true;
}
//---------------------------------------------------------------------------------------------------
bool Tga::LoadTGATexture(const char* acFileName, GLenum uiMinFilter, GLenum uiMagFilter, GLenum uiWrapMode)
{
	Tga* pkTga = new Tga;
	
	// read .tga file
	ReadTGA(acFileName, pkTga);
	if (!pkTga->m_acBits)
	{
		System::MsgBoxPrintf(RP2_ERROR, TC("Cannot load the texture file %s.tga"), acFileName);
		return false;
	}

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, uiWrapMode);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, uiWrapMode);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, uiMagFilter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, uiMinFilter);

	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexImage2D(GL_TEXTURE_2D, 0, pkTga->m_iComponents, pkTga->GetWidth(), pkTga->GetHeight(),
		0, pkTga->m_eFormat, GL_UNSIGNED_BYTE, pkTga->m_acBits);

	if( uiMinFilter == GL_LINEAR_MIPMAP_LINEAR  || 
		uiMinFilter == GL_LINEAR_MIPMAP_NEAREST ||
		uiMinFilter == GL_NEAREST_MIPMAP_LINEAR ||
		uiMinFilter == GL_NEAREST_MIPMAP_NEAREST )
		glGenerateMipmap(GL_TEXTURE_2D);	

	delete pkTga;
	pkTga = 0;

	return true;
}
//---------------------------------------------------------------------------------------------------
bool Tga::LoadTGATextureRect(const char* acFileName, GLenum uiMinFilter, GLenum uiMagFilter, GLenum uiWrapMode)
{
	Tga* pkTga = new Tga;
	
	// read .tga file
	ReadTGA(acFileName, pkTga);
	if (!pkTga->m_acBits)
	{
		System::MsgBoxPrintf(RP2_ERROR, TC("Cannot load the texture file %s.tga"), acFileName);
		return false;
	}

	glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, uiWrapMode);
	glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, uiWrapMode);

	glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, uiMinFilter);
	glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, uiMagFilter);

	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexImage2D(GL_TEXTURE_RECTANGLE, 0, pkTga->m_iComponents, pkTga->GetWidth(), pkTga->GetHeight(),
		0, pkTga->GetFormat(), GL_UNSIGNED_BYTE, pkTga->GetData());

	delete pkTga;
	pkTga = 0;
	
	return true;
}
//---------------------------------------------------------------------------------------------------